#ifndef __CMPASS_H__
#define __CMPASS_H__

#include "MColor.h"
#include <set>
#include <vector>
#include "MIteratorWrapper.h"
#include "MLight.h"
#include "MBlendMode.h"


class CMTechnique;
class CMTextureState;

// An enumeration describing which material properties should track the vertex colors.
typedef unsigned int TrackVertexColorType;

enum TrackVertexColor
{
	TVC_NONE     = 0x0 ,
	TVC_AMBIENT  = 0x1 ,        
	TVC_DIFFUSE  = 0x2 ,
	TVC_SPECULAR = 0x4 ,
	TVC_EMISSIVE = 0x8
};

// Comparison functions used for the depth/stencil buffer operations and  others.
enum _DepthFunction
{
	DF_ALWAYS_FAIL ,
	DF_ALWAYS_PASS ,
	DF_LESS ,
	DF_LESS_EQUAL ,
	DF_EQUAL ,
	DF_NOT_EQUAL ,
	DF_GREATER_EQUAL ,
	DF_GREATER
};
typedef enum _DepthFunction DepthFunction;

class CMPass
{
	//
	// typedef 
	//

public:

	typedef std::set<CMPass*> PassSet;

	typedef std::vector<CMTextureState*> TextureStateList;
	typedef VectorIterator<TextureStateList> TextureStateIterator;


	//
	// method 
	//

public:

	// constructor
	CMPass( CMTechnique* pParent , unsigned int  uiIndex );
	CMPass( CMTechnique* pParent , unsigned int  uiIndex , const CMPass& p );

	// destructor
	~CMPass( void );

	// Overloaded operator to copy on Pass to another.
	CMPass& operator=( const CMPass& rhs );

	// Gets the resource group of the ultimate parent Material
	const std::string& GetResourceGroup( void ) const;

	// Internal method for loading this pass.
	void Load( void );

	// Internal method for unloading this pass.
	void Unload( void );

	// Gets the index of this Pass in the parent Technique
	unsigned int GetIndex( void ) const { return m_uiIndex; }

	// Returns true if this pass has some element of transparency.
	bool IsTransparent( void ) const;

	// Sets the ambient color reflectance properties
	void SetAmbient( float r , float g , float b );
	void SetAmbient( const CMColor& c );

	// Sets the diffuse color reflectance properties.
	void SetDiffuse( float r , float g , float b , float a );
	void SetDiffuse( const CMColor& c );

	// Sets the specular colour reflectance properties
	void SetSpecular( float r , float g , float b , float a );
	void SetSpecular( const CMColor& c );

	// Sets the amount of self-illumination an object has.
	void SetSelfIllumination( float r , float g , float b );
	void SetSelfIllumination( const CMColor& c );

	// Sets the shininess, affecting the size of specular highlights.
	void SetShininess( float f );

	// Gets the ambient color reflectance
	const CMColor& GetAmbient( void ) const;

	// Gets the diffuse colour reflectance of the pass.
	const CMColor& GetDiffuse( void ) const;

	// Gets the specular color reflectance
	const CMColor& GetSpecular( void ) const;

	// Gets the self illumination color
	const CMColor& GetSelfIllumination( void ) const;

	// Gets the 'shininess' property (affects specular highlights).
	float GetShininess( void ) const;

	// Sets which material properties follow the vertex color
	void SetVertexColorTracking( TrackVertexColorType eTracking );

	// Gets which material properties follow the vertex color
	TrackVertexColorType GetVertexColorTracking( void ) const;

	// Sets the type of light shading required
	void SetShadingMode( CMLight::ShadeOptions eOption );

	// Returns the type of light shading to be used.
	CMLight::ShadeOptions GetShadingMode( void ) const;

	// Sets whether or not dynamic lighting is enabled.
	void SetLightingEnabled( bool bEnabled );

	// Returns whether or not dynamic lighting is enabled.
	bool GetLightingEnabled( void ) const;

	// Inserts a new TextureState object into the Pass.
	CMTextureState* CreateTextureState( void );

	// Inserts a new TextureState object into the Pass.
	CMTextureState* CreateTextureState( const std::string& strTextureName , unsigned int uiTexCoordSet = 0 );

	// Removes the indexed texture unit state from this pass.
	void RemoveTextureState( unsigned int uiIndex );

	// Removes all texture unit settings.
	void RemoveAllTextureStates( void );

	// Get an iterator over the TextureUnitStates contained in this Pass.
	const TextureStateIterator GetTextureStateIterator( void );

	// Returns the number of texture settings.
	unsigned int GetNumTextureStates( void ) const
	{
		return ( unsigned int )m_TextureStateList.size();
	}

	// Sets the kind of blending this pass has with the existing contents of the scene.
	void SetSceneBlending( const SceneBlendType eSBT );

	// Allows very fine control of blending this Pass with the existing contents of the scene.
	void SetSceneBlending( const SceneBlendFactor eSourceFactor , const SceneBlendFactor eDestFactor );

	// Retrieves the source blending factor for the material (as set using Materiall::setSceneBlending).
	SceneBlendFactor GetSourceBlendFactor( void ) const;

	// Retrieves the destination blending factor for the material (as set using Materiall::setSceneBlending).
	SceneBlendFactor GetDestBlendFactor( void ) const;

	// Sets whether or not this pass renders with depth-buffer checking on or not.
	// If depth-buffer checking is on, whenever a pixel is about to be written to the frame buffer
	// the depth buffer is checked to see if the pixel is in front of all other pixels written at that point. If not, the pixel is not written.
	void SetDepthCheckEnabled( bool bEnabled );

	// Returns whether or not this pass renders with depth-buffer checking on or not.
	bool GetDepthCheckEnabled( void ) const;

	// Sets whether or not this pass renders with depth-buffer writing on or not.
	// If depth-buffer writing is on, whenever a pixel is written to the frame buffer
	// the depth buffer is updated with the depth value of that new pixel, thus affecting future rendering operations if future pixels are behind this one.
	void SetDepthWriteEnabled( bool bEnabled );

	// Returns whether or not this pass renders with depth-buffer writing on or not.
	bool GetDepthWriteEnabled( void ) const;

	// Sets the function used to compare depth values when depth checking is on.
	// If depth checking is enabled (see setDepthCheckEnabled) a comparison occurs between the depth value of the pixel to be written and the current contents of the buffer.
	// This comparison is normally DF_LESS_EQUAL, i.e. the pixel is written if it is closer (or at the same distance) than the current contents. If you wish you can change this comparison using this method.
	void SetDepthFunction( DepthFunction eFunc );

	// Returns the function used to compare depth values when depth checking is on.
	DepthFunction GetDepthFunction( void ) const;

	// Sets the depth bias to be used for this material.
	// When polygons are coplanar, you can get problems with 'depth fighting' where the pixels from the two polys compete for the same screen pixel.
	// This is particularly a problem for decals (polys attached to another surface to represent details such as bulletholes etc.).
	void SetDepthBias( unsigned int uiBias );

	// Retrieves the depth bias value as set by setDepthValue.
	unsigned int  GetDepthBias( void ) const;


	/*
	//void SetVertexShader( Shader* pShader );
	void SetVertexShader( const String& strName , BOOL bResetParams = true );

	// Gets the vertex shader parameters used by this pass.
	ShaderParameters* GetVertexShaderParameters( void ) const;

	// Gets the vertex shader used by this pass, only available after Load().
	Shader* GetVertexShader( void );

	// Returns true if this pass uses a programmable vertex pipeline
	BOOL HasVertexShader( void ) const { return ( __pVertexShaderUsage != NULL ); }

	// Returns true if this pass uses a programmable fragment pipeline
	BOOL HasPixelShader( void ) const { return ( __pPixelShaderUsage != NULL ); }

	// Returns true if this pass is programmable ie includes either a vertex or fragment program.
	BOOL IsProgrammable( void ) const { return ( __pVertexShaderUsage || __pPixelShaderUsage ); }

	// Update any automatic parameters (except lights) on this pass
	void UpdateShaderAutoParamsNoLights( const ShaderAutoParamDataSource& ParamData ) const;
    /**/


	//
	// attribute 
	//

protected:

	// parent technique
	CMTechnique* m_pParentTechnique;

	// index
	unsigned int  m_uiIndex;

	//
	CMColor m_Ambient;
	CMColor m_Diffuse;
	CMColor m_Specular;
	CMColor m_Emissive;
	float   m_fShininess;

	TrackVertexColorType m_eTracking;

	// Shading options
	CMLight::ShadeOptions m_eShadeOption;

	// Lighting enabled?
	bool m_bLightingEnabled;

	// textrue
	TextureStateList m_TextureStateList;

	// Blending factors
	SceneBlendFactor m_eSourceBlendFactor;    
	SceneBlendFactor m_eDestBlendFactor;

	// Depth buffer settings
	bool             m_bDepthCheck;
	bool             m_bDepthWrite;
	DepthFunction __eDepthFunc;
	unsigned int __uiDepthBias;

	// shader
	//ShaderUsage* __pVertexShaderUsage;
	//ShaderUsage* __pPixelShaderUsage;

};

#endif
